package at.com.vn.chess.util;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import javax.swing.AbstractCellEditor;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

import org.jdesktop.swingx.JXHyperlink;

import at.com.vn.chess.entity.ChessRow;

/**
 * The ButtonColumn class provides a renderer and an editor that looks like a
 * JButton. The renderer and editor will then be used for a specified column in
 * the table. The TableModel will contain the String to be displayed on the
 * button.
 * 
 * The button can be invoked by a mouse click or by pressing the space bar when
 * the cell has focus. Optionaly a mnemonic can be set to invoke the button.
 * When the button is invoked the provided Action is invoked. The source of the
 * Action will be the table. The action command will contain the model row
 * number of the button that was clicked.
 * 
 */
public class HyperLinkColumn extends AbstractCellEditor implements
		TableCellRenderer, TableCellEditor, ActionListener, MouseListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JTable table;
	private Action action;
	private int mnemonic;
	private Border originalBorder;
	private Border focusBorder;

	private JXHyperlink renderButton;
	private JXHyperlink editButton;
	private Object editorValue;
	private boolean isButtonColumnEditor;

	ArrayList<ChessRow> rowEff;

	/**
	 * Create the ButtonColumn to be used as a renderer and editor. The renderer
	 * and editor will automatically be installed on the TableColumn of the
	 * specified column.
	 * 
	 * @param table the table containing the button renderer/editor
	 * @param action the Action to be invoked when the button is invoked
	 * @param column the column to which the button renderer/editor is added
	 */
	public HyperLinkColumn( JTable table, Action action, ArrayList<ChessRow> rowEff ) {
		this.table = table;
		this.action = action;
		this.rowEff = rowEff;

		renderButton = new JXHyperlink( action );
		editButton = new JXHyperlink( action );
		editButton.setFocusPainted( false );
		editButton.addActionListener( this );
		originalBorder = editButton.getBorder();
		setFocusBorder( new LineBorder( Color.BLUE ) );

		TableColumnModel columnModel = table.getColumnModel();

		// columnModel.getColumn(1).setCellRenderer(this);
		// columnModel.getColumn(2).setCellRenderer(this);
		columnModel.getColumn( 3 ).setCellRenderer( this );

		// columnModel.getColumn(1).setCellEditor(this);
		// columnModel.getColumn(2).setCellEditor(this);
		columnModel.getColumn( 3 ).setCellEditor( this );

		table.addMouseListener( this );
	}

	/**
	 * Get foreground color of the button when the cell has focus
	 * 
	 * @return the foreground color
	 */
	public Border getFocusBorder() {
		return focusBorder;
	}

	/**
	 * The foreground color of the button when the cell has focus
	 * 
	 * @param focusBorder the foreground color
	 */
	public void setFocusBorder( Border focusBorder ) {
		this.focusBorder = focusBorder;
		editButton.setBorder( focusBorder );
	}

	public int getMnemonic() {
		return mnemonic;
	}

	/**
	 * The mnemonic to activate the button when the cell has focus
	 * 
	 * @param mnemonic the mnemonic
	 */
	public void setMnemonic( int mnemonic ) {
		this.mnemonic = mnemonic;
		renderButton.setMnemonic( mnemonic );
		editButton.setMnemonic( mnemonic );
	}

	private ChessRow getChessRow( int currentRow, JTable table ) {
		for ( ChessRow iRow : rowEff ) {
			Object o = table.getValueAt( currentRow, 0 );
			if ( Integer.valueOf( String.valueOf( o ) ) == iRow.getTableId() ) {
				return iRow;
			}
		}
		return null;
	}

	@Override
	public Component getTableCellEditorComponent( JTable table, Object value,
			boolean isSelected, int row, int column ) {

		ChessRow iRow = getChessRow( row, table );
		if ( iRow != null ) {
			if ( column == 3 ) {
				if ( value == null ) {
					editButton.setText( "" );
					editButton.setIcon( null );
				} else if ( value instanceof Icon ) {
					editButton.setText( "" );
					editButton.setIcon( ( Icon ) value );
				} else {
					editButton.setText( "<html><u>" + String.valueOf( value )
							+ "</u></html>" );
					editButton.setIcon( null );
				}

				this.editorValue = value;
				return editButton;
			}
		}
		JLabel lb = new JLabel( String.valueOf( table.getValueAt( row, column ) ) );
		lb.setForeground( Color.BLACK );
		this.editorValue = table.getValueAt( row, column );
		return lb;
	}

	@Override
	public Object getCellEditorValue() {
		return editorValue;
	}

	//
	// Implement TableCellRenderer interface
	//
	public Component getTableCellRendererComponent( JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column ) {
		ChessRow iRow = getChessRow( row, table );
		if ( iRow != null ) {
			if ( column == 3 ) {
				if ( isSelected ) {
					renderButton.setForeground( Color.BLUE );
					renderButton.setBackground( table.getSelectionBackground() );
				} else {
					renderButton.setForeground( Color.BLUE );
					renderButton.setBackground( UIManager
							.getColor( "Button.background" ) );
				}

				if ( hasFocus ) {
					renderButton.setBorder( focusBorder );
				} else {
					renderButton.setBorder( originalBorder );
				}

				// renderButton.setText( (value == null) ? "" : value.toString()
				// );
				if ( value == null ) {
					renderButton.setText( "" );
					renderButton.setIcon( null );
				} else if ( value instanceof Icon ) {
					renderButton.setText( "" );
					renderButton.setIcon( ( Icon ) value );
				} else {
					if ( column == 3 ) {
						renderButton.getAction()
								.putValue( Action.SHORT_DESCRIPTION, "view chess" );
					} else {
						renderButton
								.getAction()
								.putValue( Action.SHORT_DESCRIPTION, "join to play chess" );
					}
					renderButton.setText( "<html><u>" + String.valueOf( value )
							+ "</u></html>" );
					renderButton.setIcon( null );
				}
				return renderButton;
			}
		}
		JLabel lb = new JLabel( String.valueOf( table.getValueAt( row, column ) ) );
		lb.setForeground( Color.BLACK );
		return lb;
	}

	/*
	 * When the mouse is pressed the editor is invoked. If you then then drag
	 * the mouse to another cell before releasing it, the editor is still
	 * active. Make sure editing is stopped when the mouse is released.
	 */
	public void mousePressed( MouseEvent e ) {
		if ( table.isEditing() && table.getCellEditor() == this )
			isButtonColumnEditor = true;
	}

	public void mouseReleased( MouseEvent e ) {
		if ( isButtonColumnEditor && table.isEditing() )
			table.getCellEditor().stopCellEditing();

		isButtonColumnEditor = false;
	}

	public void mouseClicked( MouseEvent e ) {
	}

	public void mouseEntered( MouseEvent e ) {
	}

	public void mouseExited( MouseEvent e ) {
	}

	@Override
	public void actionPerformed( ActionEvent e ) {
		int row = table.convertRowIndexToModel( table.getEditingRow() );
		int column = table.convertColumnIndexToModel( table.getEditingColumn() );
		fireEditingStopped();

		// Invoke the Action

		ActionEvent event = new ActionEvent( table, ActionEvent.ACTION_PERFORMED,
				row + "," + column );
		action.actionPerformed( event );
	}
}
